#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "simpledeviceitem.h"
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QTabWidget>
#include <QMessageBox>
#include <QPainter>
#include <QToolBar>
#include <QAction>
#include <QGraphicsLineItem>
#include <QtMath>
#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QDateTime>
#include <QDebug>
#include <QFormLayout>
#include <QLineEdit>
#include <QTimer>
#include <QDialog>
#include <QPushButton>
#include <QVariantMap>

#include <QFileDialog>
#include <QTextStream>
#include <QVBoxLayout>
#include <QDoubleValidator>
#include <algorithm>

// 初始化曲线图表
void MainWindow::initChart()
{
    if (m_chartView) {
        delete m_chartView;
        m_chartView = nullptr;
    }

    m_chart = new QChart();
    m_chart->setTitle("组件功率曲线");
    m_chart->legend()->setVisible(true);
    m_chart->legend()->setAlignment(Qt::AlignBottom);

    // 横坐标：时间（小时）
    QValueAxis *axisX = new QValueAxis();
    axisX->setTitleText("时间 (小时)");
    axisX->setLabelFormat("%d");
    axisX->setRange(0, m_csvData.size());  // 默认范围：0 ~ 行数

    // 纵坐标：功率
    QValueAxis *axisY = new QValueAxis();
    axisY->setTitleText("功率 (kW)");
    axisY->setLabelFormat("%.1f");

    m_chart->addAxis(axisX, Qt::AlignBottom);
    m_chart->addAxis(axisY, Qt::AlignLeft);

    // 放到第二个 tab 页面
    QTabWidget *tabs = this->findChild<QTabWidget*>("tabWidget");
    if (tabs) {
        QWidget *curveTab = tabs->widget(1);
        if (curveTab) {
            QVBoxLayout *layout = new QVBoxLayout(curveTab);
            m_chartView = new QChartView(m_chart, curveTab);
            m_chartView->setRenderHint(QPainter::Antialiasing);
            layout->addWidget(m_chartView);
            curveTab->setLayout(layout);
        }
    }
}


// 导出曲线到 CSV
void MainWindow::exportCurvesToCsv(const QString &filePath)
{
    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        QMessageBox::warning(this, "导出失败", "无法打开文件: " + filePath);
        return;
    }

    QTextStream out(&file);
    // 表头
    out << "time";
    for (const QString &compId : m_seriesMap.keys()) {
        out << "," << compId;
    }
    out << "\n";

    // 获取最大时间步
    int maxSteps = 0;
    for (QLineSeries *series : m_seriesMap.values()) {
        maxSteps = std::max(maxSteps, (int)series->count());
    }

    // 输出逐行数据
    for (int t = 0; t < maxSteps; ++t) {
        out << t;
        for (QLineSeries *series : m_seriesMap.values()) {
            if (t < series->count()) {
                out << "," << series->at(t).y();
            } else {
                out << ",";
            }
        }
        out << "\n";
    }

    file.close();
    QMessageBox::information(this, "导出成功", "曲线已导出到 " + filePath);
}

// 清空曲线
void MainWindow::clearCurves()
{
    if (m_chart) {
        m_chart->removeAllSeries();
    }
    m_seriesMap.clear();
}
void MainWindow::appendCurvePoint(const QString &compId, double value, int tIndex)
{
    if (!m_chart) return;

    if (!m_seriesMap.contains(compId)) {
        QLineSeries *series = new QLineSeries();
        series->setName(compId);
        m_chart->addSeries(series);

        for (QAbstractAxis *axis : m_chart->axes(Qt::Horizontal))
            series->attachAxis(axis);
        for (QAbstractAxis *axis : m_chart->axes(Qt::Vertical))
            series->attachAxis(axis);

        m_seriesMap[compId] = series;
    }

    m_seriesMap[compId]->append(tIndex, value);

    // 自动调整纵坐标范围
    double minY = std::numeric_limits<double>::max();
    double maxY = std::numeric_limits<double>::lowest();
    for (QLineSeries *s : m_seriesMap.values()) {
        for (auto &p : s->points()) {
            minY = std::min(minY, p.y());
            maxY = std::max(maxY, p.y());
        }
    }
    if (maxY > minY) {
        if (!m_chart->axes(Qt::Vertical).isEmpty()) {
            auto axisY = qobject_cast<QValueAxis*>(m_chart->axes(Qt::Vertical).first());
            if (axisY) axisY->setRange(minY * 0.9, maxY * 1.1);
        }
    }

    // 🔥 强制刷新
    m_chart->update();
    if (m_chartView) m_chartView->repaint();
    // 限制 X 轴范围，只显示最近 24 点
    int windowSize = 24; // 显示24小时
    int maxX = tIndex;
    int minX = std::max(0, tIndex - windowSize);

    if (!m_chart->axes(Qt::Horizontal).isEmpty()) {
        auto axisX = qobject_cast<QValueAxis*>(m_chart->axes(Qt::Horizontal).first());
        if (axisX) axisX->setRange(minX, maxX);
    }
}

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // 创建场景并绑定到 ui 的 QGraphicsView（确保 ui 中有 graphicsView）
    // 在 UI 中查找名为 "graphicsView" 的 QGraphicsView（避免直接依赖生成的 ui_mainwindow.h）
    m_scene = new QGraphicsScene(this);
    QGraphicsView *view = this->findChild<QGraphicsView*>("graphicsView");
    if (view) {
        view->setScene(m_scene);
        view->setRenderHint(QPainter::Antialiasing);
    }

    // 在属性tab中找到一个容器并插入 QTextEdit 用于显示属性
    QWidget *propTab = this->findChild<QWidget*>("tab");
    if (propTab) {
        m_propText = new QTextEdit(propTab);
        m_propText->setReadOnly(true);
        m_propText->setGeometry(propTab->rect().adjusted(10,10,-10,-10));
        m_propText->show();
    }

    // 不需要实时更新时间，初始化属性面板为固定的中午12:00快照数据

    if (m_propText) {
        QString init = "--- 时间: 12:00 ---\n";
        init += "柴油发电: 0 kW, 成本: 0 元/小时\n";
        init += "光伏发电: 669.8 kW\n";
        init += "储能: 0 kW, 剩余: 700 kWh\n";
        init += "负载: 300 kW\n";
        init += "电网交换: 200 kW, 成本: 160 元/小时\n";
        init += "总功率: 1169.8 kW, 总成本: 160 元/小时\n";
        m_propText->setPlainText(init);
    }

    // 添加简朴设备
    // 图片路径（图片文件位于 resources/image/ 目录）
    QDir appDir(QCoreApplication::applicationDirPath());
    QDir projectDir = appDir;
    projectDir.cdUp(); // try to reach project root if running from build dir

    // Build a list of root candidates to search for resources
    QStringList roots;
    roots << appDir.absolutePath();
    roots << projectDir.absolutePath();
    // try two levels up as well
    {
        QDir up = projectDir;
        up.cdUp();
        roots << up.absolutePath();
    }
    roots << QDir::currentPath();
    // also add the explicit project path common in this workspace
    roots << QDir("C:/xiaozuzuoye_z/project").absolutePath();

    auto findImage = [&](const QString &name)->QString {
        for (const QString &root : roots) {
            QString p1 = QDir(root).filePath("resources/image/" + name);
            QString p2 = QDir(root).filePath("resources/" + name);
            if (QFile::exists(p1)) {
                qDebug() << "Found image" << name << "at" << p1;
                return p1;
            }
            if (QFile::exists(p2)) {
                qDebug() << "Found image" << name << "at" << p2;
                return p2;
            }
        }
        return QString();
    };

    auto diesel = new SimpleDeviceItem("diesel_1", "柴油机", findImage("diesel.png"));
    // 左中
    diesel->setPos(-120, -20);
    m_scene->addItem(diesel);
    connect(diesel, &SimpleDeviceItem::editRequested, this, &MainWindow::onEditComponentRequested);
    connect(diesel, &SimpleDeviceItem::viewCurveRequested, this, &MainWindow::onViewComponentCurve);

    auto pv = new SimpleDeviceItem("pv_1", "光伏", findImage("pv.png"));
    // 右中
    pv->setPos(160, -20);
    m_scene->addItem(pv);
    connect(pv, &SimpleDeviceItem::editRequested, this, &MainWindow::onEditComponentRequested);
    connect(pv, &SimpleDeviceItem::viewCurveRequested, this, &MainWindow::onViewComponentCurve);

    auto battery = new SimpleDeviceItem("bat_1", "储能", findImage("storage.png"));
    // 左下
    battery->setPos(-60, 140);
    m_scene->addItem(battery);
    connect(battery, &SimpleDeviceItem::editRequested, this, &MainWindow::onEditComponentRequested);
    connect(battery, &SimpleDeviceItem::viewCurveRequested, this, &MainWindow::onViewComponentCurve);
    
    // 添加主电网与负载，方便展示连接
    auto grid = new SimpleDeviceItem("grid_1", "主电网", findImage("grid.png"));
    // 顶部中间
    grid->setPos(20, -180);
    m_scene->addItem(grid);
    connect(grid, &SimpleDeviceItem::editRequested, this, &MainWindow::onEditComponentRequested);
    connect(grid, &SimpleDeviceItem::viewCurveRequested, this, &MainWindow::onViewComponentCurve);

    auto load = new SimpleDeviceItem("load_1", "负载", findImage("load.png"));
    // 右下
    load->setPos(160, 140);
    m_scene->addItem(load);
    connect(load, &SimpleDeviceItem::editRequested, this, &MainWindow::onEditComponentRequested);
    connect(load, &SimpleDeviceItem::viewCurveRequested, this, &MainWindow::onViewComponentCurve);

    // 创建若干连接（带箭头）
    addConnection(pv->pos(), load->pos());
    addConnection(grid->pos(), load->pos());
    addConnection(pv->pos(), battery->pos());
    addConnection(battery->pos(), load->pos());

    // 创建工具栏
    createToolbar();

    // 查找CSV文件
    auto findCsv = [&](const QString &name)->QString {
        for (const QString &root : roots) {
            QString p1 = QDir(root).filePath("resources/" + name);
            QString p2 = QDir(root).filePath(name);
            if (QFile::exists(p1)) {
                qDebug() << "Found CSV" << name << "at" << p1;
                return p1;
            }
            if (QFile::exists(p2)) {
                qDebug() << "Found CSV" << name << "at" << p2;
                return p2;
            }
        }
        qDebug() << "CSV not found in candidates:" << name;
        return QString();
    };

    QString csvPath = findCsv("参考数据.csv");
    if (!csvPath.isEmpty()) {
        loadCsv(csvPath);
    } else {
        qWarning() << "无法找到参考数据.csv文件";
    }
    m_timeTimer = new QTimer(this);
    connect(m_timeTimer, &QTimer::timeout, this, &MainWindow::updateFromCsv);
    // 将每步间隔调慢以便更好计算/判断，单位毫秒（这里设为 2000ms -> 每行数据步进代表 1 小时）
    m_timeTimer->start(2000);
    initChart();


}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::addConnection(const QPointF &from, const QPointF &to)
{
    // 画直线
    // no-op: connections are disabled (no lines drawn)
    Q_UNUSED(from)
    Q_UNUSED(to)
}

void MainWindow::loadCsv(const QString &filePath)
{
    m_csvData.clear();
    m_csvIndex = 0;

    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qWarning() << "无法打开文件:" << filePath;
        return;
    }

    QTextStream in(&file);
    QString headerLine = in.readLine(); // 第一行表头
    // 去除可能的 BOM 并修剪空白
    if (headerLine.startsWith("\xEF\xBB\xBF")) headerLine = headerLine.mid(3);
    QStringList headers;
    for (const QString &h : headerLine.split(",")) {
        headers << h.trimmed();
    }
    qDebug() << "CSV headers:" << headers;

    while (!in.atEnd()) {
        QString line = in.readLine();
        if (line.trimmed().isEmpty()) continue;

        QStringList fields;
        for (const QString &f : line.split(",")) fields << f.trimmed();
        QVariantMap row;
        for (int i = 0; i < headers.size() && i < fields.size(); ++i) {
            row[headers[i]] = fields[i];
        }
        if (m_csvData.isEmpty()) qDebug() << "First data row (sample):" << row;
        m_csvData.append(row);
    }
    file.close();

    qDebug() << "CSV 行数:" << m_csvData.size();
}


void MainWindow::updateFromCsv()
{
    if (m_csvData.isEmpty()) return;

    QVariantMap row = m_csvData[m_csvIndex];

    // 光伏功率
    m_status["pv_1"]["power"] = row.value("归一化光伏曲线").toDouble() * 1000;

    // 负荷功率
    double loadPower = row.value("全国负荷").toDouble();
    m_status["load_1"]["power"] = loadPower;

    // 尝试从 CSV 中读取主电网功率与电价（兼容若干常见列名），找不到时使用默认值
    double gridPower = 200.0; // 默认 grid 功率
    QStringList gpCols = { "电网供电", "grid_power", "网供", "电网功率", "grid" };
    for (const QString &c : gpCols) {
        if (row.contains(c)) {
            gridPower = row.value(c).toDouble();
            qDebug() << "Using grid power from CSV column:" << c << ", value:" << gridPower;
            break;
        }
    }
    m_status["grid_1"]["power"] = gridPower;

    // 默认情况下，储能功率应为 0（没有充放电）——在后续逻辑中根据情况更新
    m_status["bat_1"]["power"] = 0.0;

    // 电价（price）优先从 CSV 读取 — CSV 中的 '市场价格' 单位为 元/千瓦时 (元/kWh)
    double marketPricePerKWh = 0.16; // 默认电价 (元/kWh)，注意：之前代码使用 160 为元/小时的误解，这里使用较小合理默认值
    QStringList marketCols = { "市场价格", "电价", "market_price", "grid_price", "电网价格", "price" };
    for (const QString &c : marketCols) {
        if (row.contains(c)) {
            marketPricePerKWh = row.value(c).toDouble();
            qDebug() << "Using market price (元/kWh) from CSV column:" << c << ", value:" << marketPricePerKWh;
            break;
        }
    }
    // 计算电网每小时成本 = 出力(kW) * 价格(元/kWh)
    double gridCostPerHour = gridPower * marketPricePerKWh;
    m_status["grid_1"]["cost"] = gridCostPerHour;
    // 也保存单价以备显示或后续计算
    m_status["grid_1"]["price_per_kwh"] = marketPricePerKWh;

    // 柴油机效率和燃油价格：优先从燃料相关列读取，否则使用默认燃油价格（元/单位燃料）
    double efficiency = 0.35;  // 假设效率 35%
    double fuelPrice = 1.0; // 默认燃料价格（单位由你定义，保持与之前计算一致）
    QStringList fuelCols = { "燃油价格", "fuel_price", "燃料价格", "fuelPrice" };
    bool foundFuel = false;
    for (const QString &c : fuelCols) {
        if (row.contains(c)) {
            fuelPrice = row.value(c).toDouble();
            qDebug() << "Using fuel price from CSV column:" << c << ", value:" << fuelPrice;
            foundFuel = true;
            break;
        }
    }
    if (!foundFuel) {
        // silently use default fuelPrice when CSV doesn't provide it
    }

    // 智能调度：当能读取到 marketPricePerKWh 时，不再固定使用 gridPower=200
    double pvPower = m_status["pv_1"]["power"].toDouble();

    // 简单电池模型参数（可后续从配置或对象读取）
    double storageCapacityKwh = 1000.0; // 总容量 kWh
    double maxChargePower = 200.0; // kW
    double maxDischargePower = 200.0; // kW
    double chargeEff = 0.9;
    double dischargeEff = 0.9;

    // 从 m_status 读取当前剩余能量（kWh），若没有则默认 700 kWh
    double currentEnergy = m_status.value("bat_1").value("remaining", 0.0).toDouble();

    double dieselMax = 250.0; // 默认柴油机最大出力 kW
    double dieselMin = 10.0;  // 默认最小出力 kW

    // 如果 CSV 行里包含柴油机参数（PMAX/PMIN），从 CSV 读取并保存
    if (row.contains("PMAX")) dieselMax = row.value("PMAX").toDouble();
    if (row.contains("PMIN")) dieselMin = row.value("PMIN").toDouble();

    // 使用统一的柴油单价/单价优先级：m_status["diesel_1"]["unit_price"]（若存在），否则默认 170 元/kW
    double dieselUnitPrice = m_status["diesel_1"].value("unit_price", 170.0).toDouble();

    double gridImport = 0.0;
    double dieselPower = 0.0;

    double netLoad = loadPower - pvPower; // 正表示需要外部补充

    if (netLoad <= 0) {
        // 光伏超过负荷，优先把溢出充入储能
        double surplus = -netLoad; // kW
        double canCharge = std::min(maxChargePower, surplus);
        // 计算可接受的能量（kWh）在 1 小时步长下
        double availableCapacity = std::max(0.0, storageCapacityKwh - currentEnergy);
        double chargeEnergy = std::min(canCharge, availableCapacity); // kW ~ kWh for 1h
        // 考虑充电效率
        double chargedEnergy = chargeEnergy * chargeEff; // kWh stored during this 1h step
        currentEnergy += chargedEnergy;
        if (currentEnergy > storageCapacityKwh) currentEnergy = storageCapacityKwh;
        // 当光伏为储能充电时，按用户要求显示为正值（充电功率）
        m_status["bat_1"]["power"] = chargeEnergy; // kW
        // 保存剩余能量到状态，以便下一步使用
        m_status["bat_1"]["remaining"] = currentEnergy;
        // 此时不需要从电网或柴油机购电
        gridImport = 0.0;
        dieselPower = 0.0;
    } else {
        // 需要补充电量：比较柴油单价和市场电价，选择成本更低的来源
        if (marketPricePerKWh > 0 && dieselUnitPrice < marketPricePerKWh) {
            // 优先使用柴油机（直到达到 dieselMax 或满足负荷）
            dieselPower = std::min(dieselMax, netLoad);
            if (dieselPower < dieselMin) dieselPower = 0.0; // 如果小于最小出力则不启机
            double remaining = netLoad - dieselPower;
            gridImport = remaining > 0 ? remaining : 0.0;
        } else {
            // 优先从电网购电
            gridImport = netLoad;
            dieselPower = 0.0;
        }
        // 如果电网购电为负（不太可能），置零
        if (gridImport < 0) gridImport = 0.0;
        // 储能放电以应对部分需求：计算可放电输出（考虑能量与功率限制和放电效率）
        double availableOutput = std::min(maxDischargePower, currentEnergy * dischargeEff); // kW for 1h
        double dischargeAvailable = availableOutput;
        // 使用固定的柴油单价作为边际成本
        double dieselMarginal = dieselUnitPrice;
        // 依次针对成本更高的能源使用电池放电来替代（优先替代边际成本高的）
        for (int iter = 0; iter < 2 && dischargeAvailable > 1e-6; ++iter) {
            // Decide target: if grid price higher than diesel marginal, reduce grid; else reduce diesel
            if (gridImport > 0 && marketPricePerKWh >= dieselMarginal) {
                double reduce = std::min(dischargeAvailable, gridImport);
                gridImport -= reduce;
                dischargeAvailable -= reduce;
                // 消耗电池能量（考虑效率）
                double energyConsumed = reduce / dischargeEff; // kWh
                currentEnergy -= energyConsumed;
                // 标记电池输出为负（放电）按用户要求
                m_status["bat_1"]["power"] = - (availableOutput - dischargeAvailable);
            } else if (dieselPower > 0) {
                double reduce = std::min(dischargeAvailable, dieselPower);
                dieselPower -= reduce;
                dischargeAvailable -= reduce;
                double energyConsumed = reduce / dischargeEff;
                currentEnergy -= energyConsumed;
                m_status["bat_1"]["power"] = - (availableOutput - dischargeAvailable);
            } else if (gridImport > 0) {
                double reduce = std::min(dischargeAvailable, gridImport);
                gridImport -= reduce;
                dischargeAvailable -= reduce;
                double energyConsumed = reduce / dischargeEff;
                currentEnergy -= energyConsumed;
                m_status["bat_1"]["power"] = - (availableOutput - dischargeAvailable);
            } else {
                break;
            }
            if (currentEnergy < 0) { currentEnergy = 0; dischargeAvailable = 0; break; }
        }
        // 更新剩余能量并保存
        if (currentEnergy < 0) currentEnergy = 0;
        if (currentEnergy > storageCapacityKwh) currentEnergy = storageCapacityKwh;
        m_status["bat_1"]["remaining"] = currentEnergy;
        // 如果没有发生放电/充电，确保 power 显示为 0（上面已设置默认）
        if (!m_status["bat_1"].contains("power")) m_status["bat_1"]["power"] = 0.0;
    }

    // 更新状态
    m_status["grid_1"]["power"] = gridImport;
    m_status["diesel_1"]["power"] = dieselPower;

    // 成本计算
    double gridCostPerHourNew = gridImport * marketPricePerKWh;
    m_status["grid_1"]["cost"] = gridCostPerHourNew;
    // 使用固定单价计算柴油成本：成本 = 单价 * 功率
    double dieselCost = dieselPower * dieselUnitPrice;
    m_status["diesel_1"]["cost"] = dieselCost;
    // 保存单价以便 UI 读取
    m_status["diesel_1"]["unit_price"] = dieselUnitPrice;
    // 保存 fuel price 与 efficiency 以便后续重新计算
    m_status["diesel_1"]["fuel_price"] = fuelPrice;
    m_status["diesel_1"]["efficiency"] = efficiency;

    // 刷新显示
    restoreOverallSnapshot();
    appendCurvePoint("pv_1", m_status["pv_1"]["power"].toDouble(), m_csvIndex);
    appendCurvePoint("diesel_1", dieselPower, m_csvIndex);
    appendCurvePoint("load_1", loadPower, m_csvIndex);

    // 下一行
    m_csvIndex++;
    if (m_csvIndex >= m_csvData.size()) {
        m_csvIndex = 0;
    }
}


void MainWindow::createToolbar()
{
    QToolBar *tb = addToolBar(tr("工具"));
    // 添加一个可切换的暂停/继续按钮
    QAction *pauseAction = tb->addAction(tr("暂停"));
    pauseAction->setCheckable(true);
    pauseAction->setChecked(false);
    connect(pauseAction, &QAction::toggled, this, &MainWindow::onPauseToggled);
}

// Removed import/simulate/export slot implementations (toolbar actions replaced by pause toggle)

void MainWindow::onPauseToggled(bool paused)
{
    if (paused) {
        if (m_timeTimer && m_timeTimer->isActive()) m_timeTimer->stop();
        qDebug() << "Simulation paused";
    } else {
        if (m_timeTimer && !m_timeTimer->isActive()) m_timeTimer->start(2000);
        qDebug() << "Simulation resumed";
    }
}

void MainWindow::onEditComponentRequested(const QString &compId)
{
    // 显示该组件的属性到属性面板
    updatePropertyDisplay(compId);
    // 打开参数编辑对话框
    showEditDialogForComponent(compId);
}

void MainWindow::showEditDialogForComponent(const QString &compId)
{
    // 根据组件类型决定显示哪些字段
    QStringList fields;
    if (compId.startsWith("diesel")) fields << "power" << "cost";
    else if (compId.startsWith("pv")) fields << "power";
    else if (compId.startsWith("load")) fields << "power";
    else if (compId.startsWith("grid")) fields << "power" << "cost";
    else if (compId.startsWith("bat")) fields << "power" << "soc";
    else fields << "power";

    QDialog dlg(this);
    dlg.setWindowTitle(tr("编辑参数 - %1").arg(compId));
    QFormLayout *form = new QFormLayout(&dlg);
    QMap<QString, QLineEdit*> edits;
    QVariantMap st = m_status.value(compId);
    
    for (const QString &f : fields) {
        QLineEdit *le = new QLineEdit(&dlg);
        if (st.contains(f)) {
            // 特殊处理：如果是电网或柴油机的 cost 字段，界面上显示为单价（元/kW）
            if ((compId.startsWith("grid") || compId.startsWith("diesel")) && f == "cost") {
                double unit_price = 0.0;
                if (compId.startsWith("grid")) {
                    unit_price = st.value("price_per_kwh", 0.0).toDouble();
                } else if (compId.startsWith("diesel")) {
                    unit_price = st.value("unit_price", 170.0).toDouble();
                }
                le->setText(QString::number(unit_price));
            } else {
                le->setText(QString::number(st[f].toDouble()));
            }
        }
        // 如果是电网或柴油机的 cost 字段，显示标签为 price (元/kW) 并添加非负验证器
        if ((compId.startsWith("grid") || compId.startsWith("diesel")) && f == "cost") {
            QDoubleValidator *validator = new QDoubleValidator(0, 1e6, 6, le);
            validator->setNotation(QDoubleValidator::StandardNotation);
            le->setValidator(validator);
            form->addRow(tr("price (元/kW):"), le);
        } else {
            form->addRow(f + ":", le);
        }
        edits[f] = le;
    }
    // OK button triggers update
    QPushButton *ok = new QPushButton(tr("确定"));
    form->addRow(ok);
    connect(ok, &QPushButton::clicked, &dlg, &QDialog::accept);
    // allow Enter to accept
    dlg.setLayout(form);
    if (dlg.exec() == QDialog::Accepted) {
        // save values back to m_status
        QVariantMap &map = m_status[compId];
        for (auto it = edits.begin(); it != edits.end(); ++it) {
            bool okv = false;
            double val = it.value()->text().toDouble(&okv);
            if (okv) map[it.key()] = val;
        }
        // update overall snapshot and return to main snapshot display
        // 如果修改的是主电网（grid_x），把 cost 当作单价（元/kWh）保存为 price_per_kwh
        if (compId.startsWith("grid")) {
            if (map.contains("cost")) {
                double ppk = map.value("cost").toDouble();
                map["price_per_kwh"] = ppk;
            }
        }
        // 如果修改的是柴油机（diesel_x），把 cost 当作单价（元/kW）保存为 unit_price
        if (compId.startsWith("diesel")) {
            if (map.contains("cost")) {
                double unit_price = map.value("cost").toDouble();
                map["unit_price"] = unit_price;
            }
        }
        // 重新计算相关的总成本（电网小时成本、柴油机成本等）
        recalcCosts();
        restoreOverallSnapshot();
    }
}

void MainWindow::recalcCosts()
{
    // 重新计算主电网成本与柴油机成本，基于当前 m_status
    double gridPower = m_status.value("grid_1").value("power", 0).toDouble();
    double marketPricePerKWh = m_status.value("grid_1").value("price_per_kwh", 0.0).toDouble();
    double gridCostPerHour = gridPower * marketPricePerKWh;
    m_status["grid_1"]["cost"] = gridCostPerHour;

    // 使用固定单价计算柴油机成本：成本 = 单价 * 功率
    double dieselPower = m_status.value("diesel_1").value("power", 0).toDouble();
    double dieselUnitPrice = m_status.value("diesel_1").value("unit_price", 170.0).toDouble();
    double dieselCost = dieselPower * dieselUnitPrice;
    m_status["diesel_1"]["cost"] = dieselCost;
    m_status["diesel_1"]["unit_price"] = dieselUnitPrice;
}

void MainWindow::restoreOverallSnapshot()
{
    if (!m_propText) return;

    // gather data from m_status
    double diesel_p = m_status.value("diesel_1").value("power", 0.0).toDouble();
    double diesel_cost = m_status.value("diesel_1").value("cost", 0.0).toDouble();
    double pv_p = m_status.value("pv_1").value("power", 0.0).toDouble();
    double bat_p = m_status.value("bat_1").value("power", 0.0).toDouble();
    double bat_remaining = m_status.value("bat_1").value("remaining", 0.0).toDouble();
    double load_p = m_status.value("load_1").value("power", 0.0).toDouble();
    double grid_p = m_status.value("grid_1").value("power", 0.0).toDouble();
    double grid_cost = m_status.value("grid_1").value("cost", 0.0).toDouble();

    double total_p = diesel_p + pv_p + bat_p + grid_p;
    double total_cost = diesel_cost + grid_cost;

    // display hour wrap-around
    int displayHour = m_csvIndex;
    while (displayHour > 24) displayHour -= 24;
    QString init = QString("--- 时间: %1:00 ---\n").arg(displayHour);

    // compute unit prices (元/kW) for display
    double diesel_unit = m_status.value("diesel_1").value("unit_price", 170.0).toDouble();
    double grid_unit = m_status.value("grid_1").value("price_per_kwh", 0.0).toDouble();

    init += QString("柴油发电: %1 kW, 单价: %2 元/kW, 成本: %3 元/小时\n")
            .arg(diesel_p)
            .arg(QString::number(diesel_unit, 'f', 2))
            .arg(QString::number(diesel_cost, 'f', 2));

    init += QString("光伏发电: %1 kW\n").arg(pv_p);
    init += QString("储能: %1 kW, 剩余: %2 kWh\n").arg(bat_p).arg(QString::number(bat_remaining, 'f', 2));
    init += QString("负载: %1 kW\n").arg(load_p);

    init += QString("电网交换: %1 kW, 单价: %2 元/kW, 成本: %3 元/小时\n")
            .arg(grid_p)
            .arg(QString::number(grid_unit, 'f', 2))
            .arg(QString::number(grid_cost, 'f', 2));

    init += QString("总功率: %1 kW, 总成本: %2 元/小时\n").arg(total_p).arg(QString::number(total_cost, 'f', 2));
    m_propText->setPlainText(init);
}

void MainWindow::onViewComponentCurve(const QString &compId)
{
    // 切换到第二个 tab（功率曲线），索引为1
    QTabWidget *tabs = this->findChild<QTabWidget*>("tabWidget");
    if (tabs) tabs->setCurrentIndex(1);
    QMessageBox::information(this, tr("查看曲线"), tr("切换到功率曲线: %1").arg(compId));
}

void MainWindow::updatePropertyDisplay(const QString &compId)
{
    if (!m_propText) return;
    // 获取示例数据（如果没有则创建默认）
    QVariantMap st = m_status.value(compId);
    if (st.isEmpty()) {
        st["power"] = 0;
        st["cost"] = 0;
        st["soc"] = 70;
    }
    QString txt;
    txt += QString("组件: %1\n").arg(compId);
    double power = st.value("power", 0.0).toDouble();
    double cost = st.value("cost", 0.0).toDouble();
    txt += QString("当前功率: %1 kW\n").arg(QString::number(power, 'f', 4));

    // 如果是柴油或电网，显示单价 (元/kW) 与每小时成本 (元/小时)
    if (compId.startsWith("diesel")) {
        double unit = st.value("unit_price", 170.0).toDouble();
        txt += QString("单价: %1 元/kW, 当前成本: %2 元/小时\n").arg(QString::number(unit, 'f', 2)).arg(QString::number(cost, 'f', 2));
    } else if (compId.startsWith("grid")) {
        double unit = st.value("price_per_kwh", 0.0).toDouble();
        // fallback if not set
        if (unit <= 0.0 && power > 0.0) unit = (cost / power);
        txt += QString("单价: %1 元/kW, 当前成本: %2 元/小时\n").arg(QString::number(unit, 'f', 2)).arg(QString::number(cost, 'f', 2));
    } else {
        txt += QString("当前成本: %1 元/小时\n").arg(QString::number(cost, 'f', 2));
    }

    txt += QString("剩余能量: %1 kWh\n").arg(QString::number(st.value("remaining", 0.0).toDouble(), 'f', 2));
    txt += QString("时间: %1\n").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"));
    m_propText->setPlainText(txt);
}
//点击更新函数
void MainWindow::updateTimeTick()
{
    if (!m_propText) return;
    QString cur = m_propText->toPlainText();
    QString timeLine = QString("时间: %1").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"));
    if (cur.isEmpty() || !cur.contains("组件:")) {
        // nothing selected or only time displayed: show just time
        m_propText->setPlainText(timeLine + "\n");
        return;
    }
    // preserve existing property text, replace or append time line
    QStringList lines = cur.split('\n', Qt::SkipEmptyParts);
    if (!lines.isEmpty() && lines.last().startsWith("时间:")) {
        lines[lines.size()-1] = timeLine;
    } else {
        lines << timeLine;
    }
    m_propText->setPlainText(lines.join('\n') + "\n");

}

